<template>

  <div>
    <el-form :model="scriptData" ref="scriptData" :inline="true">
      <el-row style="background: #faf8f5; padding: 10px 10px;">
        <el-select v-model="scriptData.lang" @change="changeMode" style="margin-right: 5px;">
          <el-option v-for="mode in modes" :key="mode.value" :label="mode.label" :value="mode.value">
          </el-option>
        </el-select>
        <div style="display: inline; padding-top: 5px; padding-left: 24px;">
          <span style="font-weight: bold; color: #546E7A;" v-html="scriptData.grTitle"></span>
          <span style="font-weight: bold; color: #bababa;" v-html="' ['+scriptData.grKey+']'"></span>
          <span style="color: #bababa;" v-html="' '+scriptData.createTime"></span>
          <span style="color: #bababa;" v-html="' version:'+scriptData.version"></span>
        </div>
        <div style="display: inline; float: right;">
          <el-button type="primary" @click="handleCompare">保 存</el-button>
          <el-button @click="closeSelectedTag()">返 回</el-button>
        </div>
      </el-row>
      <el-row class="in-coder-panel">
        <div class="coder">
          <textarea ref="textarea"></textarea>
        </div>
      </el-row>
    </el-form>

    <!-- 代码版本，差异对比 对话框内容 -->
    <el-dialog :title="titleBBB" :visible.sync="openBBB">
      <div id="view"></div>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm()">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>
  </div>

</template>

<script>
    import {get, save} from "@/api/tool/groovy.js";

  // 引入全局实例
  import CodeMirror from 'codemirror'
  // 核心样式
  import 'codemirror/lib/codemirror.css'
  // 引入主题后还需要在 options 中指定主题才会生效
  import 'codemirror/theme/idea.css'

  // 需要引入具体的语法高亮库才会有对应的语法高亮效果
  // codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库
  // 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ，所以此处才把对应的 JS 提前引入
  import 'codemirror/mode/javascript/javascript.js'
  import 'codemirror/mode/css/css.js'
  import 'codemirror/mode/xml/xml.js'
  import 'codemirror/mode/shell/shell.js'
  import 'codemirror/mode/sql/sql.js'

  //代码补全提示
  import 'codemirror/addon/hint/anyword-hint.js';
  import 'codemirror/addon/hint/css-hint.js';
  import 'codemirror/addon/hint/html-hint.js';
  import 'codemirror/addon/hint/javascript-hint.js';
  //import 'codemirror/addon/hint/show-hint.css';
  import 'codemirror/addon/hint/show-hint.js';
  import 'codemirror/addon/hint/sql-hint.js';
  import 'codemirror/addon/hint/xml-hint.js';

  //代码版本差异比较
  import 'codemirror/addon/merge/merge.js'
  import 'codemirror/addon/merge/merge.css'
  import DiffMatchPatch from 'diff-match-patch'

  window.diff_match_patch = DiffMatchPatch
  window.DIFF_DELETE = -1
  window.DIFF_INSERT = 1
  window.DIFF_EQUAL = 0

  export default {
    name: "Code",

    props: {
      // 外部传入的内容，用于实现双向绑定
      value: String,
      // 外部传入的语法类型
      language: {
          type: String,
          default: null
      }
    },
    data() {
      return {
          // 内部真实的内容
          code: '#!/bin/bash\n' +
              'cd /root/\n' +
              'list=(`ls`)\n' +
              ' \n' +
              'for i in ${list[@]}\n' +
              'do\n' +
              '   if [ -d $i ]\n' +
              '   then\n' +
              '       cp -r $i /tmp/\n' +
              '   fi\n' +
              'done',
          // 默认的语法类型
          mode: 'javascript',
          // 编辑器实例
          coder: null,
          originSource: null,
          scriptData: {},//脚本对象
          // 默认配置
          options: {
              // 缩进格式
              tabSize: 4,
              // 主题，对应主题库 JS 需要提前引入
              theme: 'idea',
              line: true,
              extraKeys: {"Ctrl": "autocomplete"},
              autofocus: false,
              lineNumbers: true,   //显示行号
              smartIndent: true, // 自动缩进
              autoCloseBrackets: true// 自动补全括号
          },
          // 支持切换的语法高亮类型，对应 JS 已经提前引入
          // 使用的是 MIME-TYPE ，不过作为前缀的 text/ 在后面指定时写死了
          modes: [{
              value: 'css',
              label: 'CSS'
          }, {
              value: 'javascript',
              label: 'Javascript'
          }, {
              value: 'html',
              label: 'XML/HTML'
          }, {
              value: 'x-sh',
              label: 'Shell'
          }, {
              value: 'x-sql',
              label: 'SQL'
          },{
              value: 'x-java',
              label: 'Java'
          }],
          // 弹出层标题
          title: "",
          titleBBB: "",
          // 是否显示弹出层
          open: false,
          openBBB: false,
      }
    },
    mounted () {
        const dataId = this.$route.params && this.$route.params.dataId;//获取传入的数据id
        get(dataId).then(response => {
            this.scriptData = response.data;
            this.originSource = response.data.source;//保留原本的代码
            this._initialize();
        });
    },
    methods: {
      // 初始化
      _initialize() {
          // 初始化编辑器实例，传入需要被实例化的文本域对象和默认配置
          this.coder = CodeMirror.fromTextArea(this.$refs.textarea, this.options);
          // 编辑器赋值
          this.coder.setValue(this.scriptData.source || '');
          // 支持双向绑定
          this.coder.on('change', (coder) => {
              this.scriptData.source = coder.getValue()
              if (this.$emit) {
                  this.$emit('input', this.scriptData.source)
              }
          });
          // 尝试从父容器获取语法类型
          //console.log(this.scriptData);
          //if (this.scriptData.lang) {
          //    // 获取具体的语法类型对象
          //    let modeObj = this._getLanguage(this.scriptData.lang)
          //    console.log("lang: " + modeObj);
          //    // 判断父容器传入的语法是否被支持
          //    if (modeObj) {
          //        this.mode = modeObj.label
          //    }
          //}
      },
      // 获取当前语法类型
      _getLanguage(language){
          // 在支持的语法类型列表中寻找传入的语法类型
          return this.modes.find((mode) => {
              // 所有的值都忽略大小写，方便比较
              let currentLanguage = language.toLowerCase()
              let currentLabel = mode.label.toLowerCase()
              let currentValue = mode.value.toLowerCase()
              // 由于真实值可能不规范，例如 java 的真实值是 x-java ，所以将 value 和 label 同时和传入语法进行比较
              return currentLabel === currentLanguage || currentValue === currentLanguage
          })
      },
      // 更改模式
      changeMode(val){
          // 修改编辑器的语法配置
          this.coder.setOption('mode', `text/${val}`)
          // 获取修改后的语法
          let label = this._getLanguage(val).label.toLowerCase()
          // 允许父容器通过以下函数监听当前的语法值
          this.$emit('language-change', label)
      },
      initUI(value, orig){
          if (!value) return;
          let target = document.getElementById("view");
          target.innerHTML = "";
          CodeMirror.MergeView(target, {
              value: value,//上次内容
              origLeft: null,
              orig: orig,//本次内容
              lineNumbers: true,//显示行号
              mode: "javascript",
              highlightDifferences: true,
              styleActiveLine: false,
              matchBrackets: false,
              connect: 'align',
              readOnly: true,//只读 不可修改
              tabSize: 4,
          });
      },

      /** 按钮操作 */
      handleCompare() {
          this.openBBB = true;
          this.titleBBB = this.scriptData.grTitle + this.scriptData.createTime;
          this.$nextTick(function() {
              this.initUI(this.scriptData.source, this.originSource);
          });
      }
      ,loadData: function(dataId){
          get(dataId).then(response => {
              this.scriptData = response.data;
              console.log(this.scriptData);
          });
          return this.scriptData;
      }
      ,submitForm: function (type) {
          this.$refs["scriptData"].validate(valid => {
              if (this.scriptData.source == this.originSource) {//校验表单
                  this.$message("脚本没有更新，无需保存");
                  return;
              }
              save(this.scriptData).then(response => {
                  this.scriptData = response.data;
                  this.msgSuccess("修改成功");
                  this.openBBB = false;
              });
          });
      }
      ,cancel: function () {
          this.openBBB = false;
      }
      ,closeSelectedTag() {
          let view = this.$router.currentRoute;
          this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
              if (this.isActive(view)) {
                  this.toLastView(visitedViews, view)
              }
          });
      },
      isActive(route) {
          return route.path === this.$route.path
      },
      toLastView(visitedViews, view) {
          const latestView = visitedViews.slice(-1)[0]
          if (latestView) {
              this.$router.push(latestView.fullPath)
          } else {
              // now the default is to redirect to the home page if there is no tags-view,
              // you can adjust it according to your needs.
              if (view.name === 'Dashboard') {
                  // to reload home page
                  this.$router.replace({ path: '/redirect' + view.fullPath })
              } else {
                  this.$router.push('/')
              }
          }
      }
    }
  };
</script>

<style lang="scss">
  .in-coder-panel{
    flex-grow: 1;
    display: flex;
    position: relative;
    min-height: 500px;

    .CodeMirror {
      flex-grow: 1;
      z-index: 1;
      .CodeMirror-code {
        line-height: 19px;
      }
    }

    .code-mode-select {
      position: absolute;
      z-index: 2;
      right: 10px;
      top: 10px;
      max-width: 130px;
    }
  }
</style>

<style lang="scss">
  .coder {
    .CodeMirror {
      width: 100%;
      height: 680px;
    }
  }
</style>
